import { IAnimation } from "./AnimationPlayer";
import { CameraAnimationFrame } from "./CameraAnimationFrame";

/**
 * 由帧组成的动画
 */
export class CameraAnimation {
    private name: string = "";
    private totalTimeMs: number = 0;
    private points: CameraAnimationFrame[] = [];

    getTotalTime(): number {
        this.totalTimeMs = 0;
        this.points.forEach((p, i, a) => {
            this.totalTimeMs = Math.max(this.totalTimeMs, p.getMsTimeAnchor());
        });
        return this.totalTimeMs;
    }
    setFramesData(data: IAnimation): CameraAnimation {
        this.name = data.name;
        this.points = data.frames.map(({ name, state, time }) => { return new CameraAnimationFrame().setData(name, state, time); });
        return this;
    }
    /**
     *
     * @param data
     * @returns
     * @deprecated setPointsData
     */
    setKeyFramesData(data: { name: string; view: any; }[]): CameraAnimation {
        this.points = [];
        this.points = data.map(({ name, view }, index) => { return new CameraAnimationFrame().setData(name, view); });
        this.setTotalTimeSpliteByDistance(this.points.length * 1000); // 默认的播放时长
        return this;
    }
    /**
     * 自动按照距离分配时间
     * @param totalTimeMs
     */
    setTotalTimeSpliteByDistance(totalTimeMs: number) {
        this.totalTimeMs = totalTimeMs;
        this.buildDistance2go();
        let totalDistance2Go = this.getTotalDistance2Go();
        // 不需要动画
        if (totalDistance2Go == 0) {
            return;
        }
        this.setAllTimeAnchorBySpeed(totalDistance2Go / this.totalTimeMs);
    }
    setTotalTimeSpliteByFrame(totalTimeMs: number) {
        this.totalTimeMs = totalTimeMs;
        let totalFrameCount = this.points.length;
        if (totalFrameCount == 0) {
            return;
        }
        let timePerFrame = this.totalTimeMs / totalFrameCount;
        this.points.forEach((p, i, a) => {
            p.setMsTimeAnchor(i * timePerFrame);
        });
    }
    setAllTimeAnchorBySpeed(distancePerMs: number) {
        if (distancePerMs == 0) {
            return;
        }
        this.points.forEach((p, i, a) => {
            if (i == 0) {
                p.setMsTimeAnchor(0);
            } else {
                const preP = a[i - 1];
                p.calcMsTimeAnchor(preP.getMsTimeAnchor(), preP.getDistance2Go(), distancePerMs);
            }

        });
    }
    private getTotalDistance2Go(): number {
        let ans = 0;
        this.points.forEach(p => {
            ans += p.getDistance2Go();
        });
        return ans;
    }
    private buildDistance2go() {
        this.points.forEach((p, i, a) => {
            if (i >= a.length - 1) {
                return;
            }
            p.setDistance2go(p.getPosition().distanceTo(a[i + 1].getPosition()));
        });
    }
    update(currentAnimationTimeMs: number, viewer: Sippreep.Viewing.Viewer3D): number {
        if (this.totalTimeMs <= 0) return -1;
        let temptime = Math.min(currentAnimationTimeMs, this.totalTimeMs);
        if (this.points.length < 1) return -1;

        // 当前时间所在的两个关键帧之间
        let p1: CameraAnimationFrame, p2: CameraAnimationFrame;[p1, p2] = this.getNearly2Point(temptime);
        // const localProcess: number = this.calcProcessBy(temptime - p1.getMsTimeAnchor(), p2.getMsTimeAnchor() - p1.getMsTimeAnchor());
        // const insertionFrame = new CameraAnimationFrame().setInsertionFrameByLoaclprocess(p1, p2, localProcess);
        const insertionFrame = new CameraAnimationFrame().setInsertionFrameByAnimationTime(p1, p2, temptime);
        // 设置viewer
        const c: THREE.Camera & any = viewer.navigation.getCamera()
        if (insertionFrame.getPosition().distanceToSquared(c.position) !== 0 || insertionFrame.getTarget().distanceToSquared(c.target) !== 0) {
            viewer.navigation.setView(insertionFrame.getPosition(), insertionFrame.getTarget());
            viewer.navigation.orientCameraUp();
        }
        return temptime / this.totalTimeMs;
    }
    /**
     * 根据时间点返回这个时间点的左边关键帧和右边关键帧
     * @param temptime
     * @returns 包含两个CameraAnimationPoint
     */
    private getNearly2Point(temptime: number): CameraAnimationFrame[] {
        let brother: CameraAnimationFrame[] = [this.points[0], this.points.at(-1)!];
        for (let index = 0; index < this.points.length; index++) {
            const element: CameraAnimationFrame = this.points[index];
            if (temptime < element.getMsTimeAnchor()) {
                brother.splice(1, 1, element);
                if (index > 0) {
                    brother.splice(0, 1, this.points[index - 1]);
                }
                break;
            }
        }
        return brother;
    }
    // private calcProcessBy(partTime: number, allTime: number) {
    //     if (allTime == 0) {
    //         return 1
    //     } else {
    //         return partTime / allTime
    //     }
    // }

}
